{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "############## PLEASE RUN THIS CELL FIRST! ###################\n",
    "\n",
    "# import everything and define a test runner function\n",
    "from importlib import reload\n",
    "from helper import run\n",
    "import network\n",
    "\n",
    "from block import GENESIS_BLOCK\n",
    "from helper import calculate_new_bits\n",
    "from network import (\n",
    "    NetworkEnvelope,\n",
    "    VersionMessage,\n",
    ")"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 1\n",
    "\n",
    "Determine what this network message is:\n",
    "\n",
    "`f9beb4d976657261636b000000000000000000005df6e0e2`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 1\n",
    "\n",
    "message_hex = 'f9beb4d976657261636b000000000000000000005df6e0e2'\n",
    "\n",
    "# convert to binary\n",
    "# see what the bytes 4 through 16 aregi"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 2\n",
    "\n",
    "Write the `parse` method for `NetworkEnvelope`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch10/network.py) pass: `network.py:NetworkEnvelopeTest:test_parse`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 2\n",
    "\n",
    "reload(network)\n",
    "run(network.NetworkEnvelopeTest(\"test_parse\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 3\n",
    "\n",
    "Write the `serialize` method for `NetworkEnvelope`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch10/network.py) pass: `network.py:NetworkEnvelopeTest:test_serialize`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 3\n",
    "\n",
    "reload(network)\n",
    "run(network.NetworkEnvelopeTest(\"test_serialize\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 4\n",
    "\n",
    "Write the `serialize` method for `VersionMessage`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch10/network.py) pass: `network.py:VersionMessageTest:test_serialize`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 4\n",
    "\n",
    "reload(network)\n",
    "run(network.VersionMessageTest(\"test_serialize\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 5\n",
    "\n",
    "Write the `handshake` method for `SimpleNode`\n",
    "\n",
    "#### Make [this test](/edit/code-ch10/network.py) pass: `network.py:SimpleNodeTest:test_handshake`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 5\n",
    "\n",
    "reload(network)\n",
    "run(network.SimpleNodeTest(\"test_handshake\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### Exercise 6\n",
    "\n",
    "Write the `serialize` method for `GetHeadersMessage`.\n",
    "\n",
    "#### Make [this test](/edit/code-ch10/network.py) pass: `network.py:GetHeadersMessageTest:test_serialize`"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Exercise 6\n",
    "\n",
    "reload(network)\n",
    "run(network.GetHeadersMessageTest(\"test_serialize\"))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "from io import BytesIO\n",
    "from network import SimpleNode, GetHeadersMessage, HeadersMessage\n",
    "from block import Block, GENESIS_BLOCK, LOWEST_BITS\n",
    "from helper import calculate_new_bits\n",
    "previous = Block.parse(BytesIO(GENESIS_BLOCK))\n",
    "first_epoch_timestamp = previous.timestamp\n",
    "expected_bits = LOWEST_BITS\n",
    "count = 1\n",
    "node = SimpleNode('mainnet.programmingbitcoin.com', testnet=False)\n",
    "node.handshake()\n",
    "for _ in range(19):\n",
    "    getheaders = GetHeadersMessage(start_block=previous.hash())\n",
    "    node.send(getheaders)\n",
    "    headers = node.wait_for(HeadersMessage)\n",
    "    for header in headers.blocks:\n",
    "        if not header.check_pow():\n",
    "            raise RuntimeError('bad PoW at block {}'.format(count))\n",
    "        if header.prev_block != previous.hash():\n",
    "            raise RuntimeError('discontinuous block at {}'.format(count))\n",
    "        if count % 2016 == 0:\n",
    "            time_diff = previous.timestamp - first_epoch_timestamp\n",
    "            expected_bits = calculate_new_bits(previous.bits, time_diff)\n",
    "            print(expected_bits.hex())\n",
    "            first_epoch_timestamp = header.timestamp\n",
    "        if header.bits != expected_bits:\n",
    "            raise RuntimeError('bad bits at block {}'.format(count))\n",
    "        previous = header\n",
    "        count += 1"
   ]
  }
 ],
 "metadata": {},
 "nbformat": 4,
 "nbformat_minor": 2
}
